#include "Mailer.h"

Mailer::Mailer(System* sys, int inboxSize)
{
	m_system = sys;
	m_inbox = new BoundedBuffer(inboxSize);
	m_dispatcher = m_system->createThread(dispatch, this);

	/*****************************
	*	n+1 mailboxes:
	*	1 - Shell's mailbox
	*	n - Nodes' mailboxes
	******************************/
	m_mailboxes = new MAILBOXES();
	m_shouldRun = true;
	m_counting = true;
	m_maxQueue = 0;
}

Mailer::~Mailer(void)
{
	m_dispatcher->exit();
	MAILBOXES::iterator mailbox;
	for(mailbox = m_mailboxes->begin();mailbox!=m_mailboxes->end();mailbox++)
	{
		delete mailbox->second.mailbox;
	}
	delete m_inbox;
}

void Mailer::addMailbox(int id)
{
	MAILBOX mailbox = {id, new Buffer(), 0};
	m_mailboxes->insert(MAILBOXES::value_type(id, mailbox));
}

void* Mailer::dispatch(void* arg)
{
	Mailer* mailer = (Mailer*)arg;
	int i=0;
	while(true)
	{
		while (mailer->m_shouldRun)
		{
			mailer->m_busy = true;
			if(mailer->m_counting){
				int size = mailer->m_inbox->getSize();
				if(size > mailer->m_maxQueue) mailer->m_maxQueue = size;
			}
			Message* m = mailer->m_inbox->pop(self());
			int dest = m->getDestination();
			if(mailer->m_system->getNodeStatus(dest))
			{
				MAILBOXES* mailboxes = mailer->m_mailboxes;
				(*mailboxes)[dest].mailbox->push(m, self());				
				if(mailer->m_counting)
				{
					int size = (*mailboxes)[dest].mailbox->getSize();
					if(size > (*mailboxes)[dest].maxLength)
					(*mailboxes)[dest].maxLength = size;
				}
			}
			else
			{
				delete m;
			}
		}
		mailer->m_busy = false;
	}

}


int Mailer::send(int dest, Message *msg)
{
	int status = m_system->getNodeStatus(dest); //get dest node status from system
	
	if(status)
	{
		m_inbox->push(msg, self());
	}
	return status;
}

Message* Mailer::recieve(int id)
{
	Message* m = (*m_mailboxes)[id].mailbox->pop(self());

	return m;
}

int Mailer::getMailboxSize(int id)
{
	if(m_mailboxes->find(id) != m_mailboxes->end())
		return (*m_mailboxes)[id].mailbox->getSize();
}

void Mailer::stop()
{
	m_shouldRun = false;
}

bool Mailer::isBusy()
{
	return m_busy;
}

void Mailer::startCounting()
{
	m_counting = true;
	m_maxQueue = 0;
	
	MAILBOXES::iterator mailbox;
	for(mailbox = m_mailboxes->begin() ; mailbox!=m_mailboxes->end() ; mailbox++)
	{
		mailbox->second.maxLength = 0;
	}
}

void Mailer::stopCounting()
{
	m_counting = false;
}

int Mailer::getMaxLength()
{
	return m_maxQueue;
}

int Mailer::getInboxMaxLength(int id)
{
	if(m_mailboxes->find(id) != m_mailboxes->end())
		return (*m_mailboxes)[id].maxLength;
}

int Mailer::getTimeRequest()
{
	return m_inbox->getSize();
}

